/*
 *  Compiler.cpp
 *  Compiler
 *
 *  Created by Jacopo De Stefani on 2/14/12.
 *  Copyright 2012 Politecnico di Milano. All rights reserved.
 *
 */

#include "Compiler.h"

//Match function checks if the expected token
//from the parser equals the next scanned token.
Compiler::Compiler(const char filename[]){
    scanner = new Scanner(filename);
    Writer::getInstance();
    ExtendedSymbolTable::getInstance();
    currTok = scanner->getnextsym();
}

bool Compiler::match(Keywords matchTok){
	
	//Check and integrate with parser
	if (currTok == matchTok && currTok != ERROR) {
                
		if(currTok != PRG_END){
                        currTok = scanner->getnextsym();
                }
		return true;
        
	}
	       
	return false;
	
}

bool Compiler::programP(void){
	switch (currTok) {
		//Production 1 - program ID ; <VARS> <ROUTINELIST> <BLOCK> . $
		case PRG_INIT:
		
                    
                    
			if(match(PRG_INIT) == false){
				cerr << "Program keyword missing.\n";
				return false;
			}
			
			//TO DO : Program identifier check
			if(match(ID) == false){
				cerr << "Program identifier missing.\n";
				return false;
			}
                        
                        
                        Writer::getInstance()->initWriter(ExtendedSymbolTable::getInstance()->getLastId());
                        
                        ExtendedSymbolTable::getInstance()->setCurrScopeId(MAINSCOPE);
			ExtendedSymbolTable::getInstance()->addSymbolTableEntry(ExtendedSymbolTable::getInstance()->getLastId());
			
			if(match(ISTR_SEP) == false){
				cerr << "; missing.\n";
				return false;
			}			
			
			if(varsP(GLOBALS) == false){
				return false;
			}
			
			Writer::getInstance()->uncondJumpTo("@main");
			
			if(routinelistP() == false){
				return false;
			}
			
			Writer::getInstance()->defLabel("@main");
			
			if(blockP(GLOBALS)== false){
				return false;
			}
			
			if(match(PRG_END) == false){
				cerr << ". missing.\n";
				return false;
			}
			
			Writer::getInstance()->endProg();
			
			break;
		
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}

bool Compiler::varsP(ScopesP callerScope){
    TypesP varType;
    
	switch (currTok) {
		//Production 2 - var <IDLIST> : <TYPE> ; <VARS>
		case VAR:
			
			if(match(VAR) == false){
				cerr << "var keyword missing.\n";
				return false;
			}
			
			if(idlistP() == false){
                                return false;
			}
			
			if(match(TYPE_SEP) == false){
				cerr << ": missing.\n";
				return false;
			}			
			
			if(typeP(varType) == false){
				return false;
			}
                        
                        
                        
                        //Symbol table update - Type missing
                        if(ExtendedSymbolTable::getInstance()->updateSymbolTable(varType,callerScope,false,false) < 0 ){
                                return false;
                        }
                      
			
			if(match(ISTR_SEP) == false){
				cerr << "; missing.\n";
				return false;
			}			
	
                        
			if(varsP(callerScope)== false){
				return false;
			}
			break;
		
		//Production 3 - ε
		case FUN:
		case PROC:
		case BLK_INIT:
			//Code to execute
			break;

		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");Writer::getInstance()->errorReport(MSG,"Syntax error within variable declaration.");
			return false;
	}
	
	return true;
}

bool Compiler::idlistP(void){
	switch (currTok) {
			//Production 4 - ID<IDLIST1>
		case ID:
			//TO DO : Variable checks?
			if(match(ID) == false){
				cerr << "Variable identifier missing.\n";
				return false;
			}
			//Symbol table insertion                    
                        ExtendedSymbolTable::getInstance()->addSymbolTableEntry(ExtendedSymbolTable::getInstance()->getLastId());
                        ExtendedSymbolTable::getInstance()->pushVar(ExtendedSymbolTable::getInstance()->getLastId());
                        
			if(idlist1P() == false){
				return false;
			}
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");Writer::getInstance()->errorReport(MSG,"Syntax error near identifier list.");
			return false;
	}
	
	return true;
}

bool Compiler::idlist1P(void){
	switch (currTok) {
		
		//Production 5 - ,<IDLIST>
		case EXPR_SEP:
			if(match(EXPR_SEP) == false){
				cerr << ", missing.\n";
				return false;
			}
			
			if(idlistP() == false){
				return false;
			}
			break;
		
		//Production 6 - ε
		case TYPE_SEP:
			//Code to execute
			break;
			
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");Writer::getInstance()->errorReport(MSG,"Syntax error near identifier list.");
			return false;
	}
	
	return true;
}

bool Compiler::typeP(TypesP &type){
	switch (currTok) {
		//Production 7 - integer
		case INTEGER:
			if(match(INTEGER) == false){
				cerr << "integer keyword missing.\n";
				return false;
			}
                        type = INTT;
			break;
			
			
		//Production 8 - boolean
		case BOOLEAN:
			if(match(BOOLEAN) == false){
				cerr << "boolean keyword missing.\n";
				return false;
			}
                        type = BOOLT;
			break;
			
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");Writer::getInstance()->errorReport(MSG,"Syntax error near type specification.");
			return false;
	}
	
	return true;
}

bool Compiler::routinelistP(void){
	
	switch (currTok) {
		//Production 9 - <ROUTINE> ; <ROUTINELIST>
		case FUN:
		case PROC:
			
			if(routineP() == false){
				return false;
			}
			
			if(match(ISTR_SEP) == false){
				cerr << "; missing.\n";
				return false;
			}
			
			if(routinelistP() == false){
				return false;
			}
			
			break;
			
			
		//Production 10  - ε
		case BLK_INIT:
			//Code to execute
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}

bool Compiler::routineP(void){
	
	switch (currTok) {
		
		//Production 11 - <FUNCTION>
		case FUN:
			
			if(functionP() == false){
				return false;
			}
			
			break;
		
		//Production 12 - <PROCEDURE>
		case PROC:
			
			if(procedureP() == false){
				return false;
			}
			
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}

bool Compiler::functionP(void){
	
    string funcId;
    int sourceAddr = 0;
    TypesP retType;
    
	switch (currTok) {
			
		//Production 13 - function ID <ARGSOPT> : <TYPE> ; <VARS> <BLOCK>
		case FUN:
			
			if(match(FUN) == false){
				cerr << "function keyword missing.\n";
				return false;
			}
			
                                                
			//TO DO : Program identifier check
			if(match(ID) == false){
				cerr << "function identifier missing.\n";
				return false;
			}
                        
                        funcId = ExtendedSymbolTable::getInstance()->getLastId();
                        
                        Writer::getInstance()->defLabel(funcId); 
                        ExtendedSymbolTable::getInstance()->setCurrScopeId(funcId);
                        ExtendedSymbolTable::getInstance()->addFunctionTableEntry(funcId);
                        ExtendedSymbolTable::getInstance()->restartLocalAddress();
                        
			if(argsoptP(funcId) == false){
				return false;
			}
                        
                        
			
			if(match(TYPE_SEP) == false){
				cerr << ": missing.\n";
				return false;
			}
                        
			
			if(typeP(retType) == false){
				return false;
			}
                        
                                            
                
                        ExtendedSymbolTable::getInstance()->addSymbolTableEntry(funcId);
                        ExtendedSymbolTable::getInstance()->pushVar(funcId);
                                                                                                           
                        if(ExtendedSymbolTable::getInstance()->updateSymbolTable(retType,LOCALS,true,false) < 0 ){
                                return false;
                        }
			
                        
                    
                        
			if(match(ISTR_SEP) == false){
				cerr << "; missing.\n";
				return false;
			}	
			
			if(varsP(LOCALS) == false){
				return false;
			}
			   
			
			if(blockP(LOCALS)== false){
				return false;
			}
			
                        sourceAddr = ExtendedSymbolTable::getInstance()->getSymbolTableAttributes(funcId).getAddress();
                        
                        Writer::getInstance()->movIntTopInScope(STACKOFFSET+sourceAddr);
                        ExtendedSymbolTable::getInstance()->getSymbolTableAttributes(funcId).getTypeP() == INTT ? Writer::getInstance()->storeIntInScope(0) : Writer::getInstance()->storeBoolInScope(0); 
			Writer::getInstance()->retFunc();
			
                        ExtendedSymbolTable::getInstance()->setCurrScopeId(MAINSCOPE);
			break;
			
			
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");Writer::getInstance()->errorReport(MSG,"Missing function keyword.");
			return false;
	}
	
	return true;
}

bool Compiler::procedureP(void){
    
    string procId;
    
	switch (currTok) {
		
		//Production 14 - procedure ID <ARGSOPT> ; <VARS> <BLOCK>
		case PROC:
			
			if(match(PROC) == false){
				cerr << "procedure keyword missing.\n";
				return false;
			}
			
			//TO DO : Program identifier check
			if(match(ID) == false){
				cerr << "procedure identifier missing.\n";
				return false;
			}	
                        
                                           
                        procId = ExtendedSymbolTable::getInstance()->getLastId();
                        
                        Writer::getInstance()->defLabel(procId);
                        ExtendedSymbolTable::getInstance()->setCurrScopeId(procId);
                        ExtendedSymbolTable::getInstance()->addFunctionTableEntry(procId);
                        ExtendedSymbolTable::getInstance()->restartLocalAddress();
                        
			if(argsoptP(procId) == false){
				return false;
			}
			
			if(match(ISTR_SEP) == false){
				cerr << "; missing.\n";
				return false;
			}
                        
                        
                        ExtendedSymbolTable::getInstance()->addSymbolTableEntry(procId);
                        ExtendedSymbolTable::getInstance()->pushVar(procId);
                        
                        if( ExtendedSymbolTable::getInstance()->updateSymbolTable(PROCT,LOCALS,true,false) < 0 ){
                                return false;
                        }
			
			if(varsP(LOCALS) == false){
				return false;
			}
			
                                               
			if(blockP(LOCALS)== false){
				return false;
			}
			
			Writer::getInstance()->retProc();
			ExtendedSymbolTable::getInstance()->setCurrScopeId(MAINSCOPE);
			break;
			
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");Writer::getInstance()->errorReport(MSG,"Missing procedure keyword.");
			return false;
	}
	
	return true;
}

bool Compiler::argsoptP(string funcId){
	
	switch (currTok) {
		//Production 15 - ( var <ARGS> )
		case LST_INIT:
			
			if(match(LST_INIT) == false){
				cerr << "( missing.\n";
				return false;
			}
			
			if(match(VAR) == false){
				cerr << "var keyword missing.\n";
				return false;
			}
			
			
			if(argsP(LOCALS) == false){
				return false;
			}
			
                        ExtendedSymbolTable::getInstance()->updateTypeList(funcId);
                                                
			if(match(LST_END) == false){
				cerr << ") missing.\n";
				return false;
			}
			
			break;
			
			
		//Production 16  - ε
		case TYPE_SEP:
		case ISTR_SEP:
			//Code to execute
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}


bool Compiler::argsP(ScopesP callerScope){

    int numArgs=0;
    TypesP argsType;
    
	switch (currTok) {
			//Production 17 - <IDLIST> : <TYPE><ARGS1>
		case ID:
			
			if(idlistP() == false){
				return false;
			}
			
			if(match(TYPE_SEP) == false){
				cerr << ": missing.\n";
				return false;
			}
			
			
			if(typeP(argsType) == false){
				return false;
			}
                        
                        numArgs = ExtendedSymbolTable::getInstance()->updateSymbolTable(argsType,callerScope,false,true);
                        if(numArgs < 0){
                                return false;
                        }
                        while(numArgs != 0){
                                ExtendedSymbolTable::getInstance()->pushType(argsType);
                                numArgs--;
                        }
			
			if(args1P(callerScope) == false){
				return false;
			}
			
			break;
				
		default:Writer::getInstance()->errorReport(MSG,"Syntax error."); Writer::getInstance()->errorReport(MSG,"Syntax error near arguments declaration.");
			return false;
	}
	
	return true;
}

bool Compiler::args1P(ScopesP callerScope){
	
	switch (currTok) {
		//Production 18 - ; <ARGS>
		case ISTR_SEP:
			
			if(match(ISTR_SEP) == false){
				cerr << "; missing.\n";
				return false;
			}
			
			if(argsP(callerScope) == false){
				return false;
			}
			
			break;
			
			
		//Production 19  - ε
		case LST_END:
			//Code to execute
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");Writer::getInstance()->errorReport(MSG,"Syntax error .");Writer::getInstance()->errorReport(MSG,"Syntax error in argument list.");
			return false;
	}
	
	return true;
}

bool Compiler::blockP(ScopesP callerScope){
	
	switch (currTok) {
		
		//Production 20 - begin <STATEMENTOPT> end
		case BLK_INIT:
			
			if(match(BLK_INIT) == false){
				cerr << "begin keyword missing.\n";
				return false;
			}
		
			if(statementoptP(callerScope) == false){
				return false;
			}
			
			if(match(BLK_END) == false){
				cerr << "end keyword missing.\n";
				return false;
			}
			
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}

bool Compiler::statementoptP(ScopesP callerScope){
	
	switch (currTok) {
		
		//Production 21 - <STATEMENTLIST>
		case ID:
		case BLK_INIT:
		case IF:
		case WHILE:
		case READ:
		case WRITE:
			
			if(statementlistP(callerScope) == false){
				return false;
			}
			
			break;
			
			
		//Production 22  - ε
		case BLK_END:
			//Code to execute
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}

bool Compiler::statementlistP(ScopesP callerScope){
	
	switch (currTok) {
		//Production 23 - <STATEMENT><STLIST1>
		case ID:
		case BLK_INIT:
		case IF:
		case WHILE:
		case READ:
		case WRITE:
			
			if(statementP(callerScope) == false){
				return false;
			}
			
			if(stlist1P(callerScope) == false){
				return false;
			}
			
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}

bool Compiler::stlist1P(ScopesP callerScope){
	
	switch (currTok) {
			
		//Production 24 - ; <STATEMENTLIST>
		case ISTR_SEP:
			
			if(match(ISTR_SEP) == false){
				cerr << "; missing.\n";
				return false;
			}
			
			if(statementlistP(callerScope) == false){
				return false;
			}
			
			break;
			
			
		//Production 25  - ε
		case BLK_END:
			//Code to execute
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}

bool Compiler::statementP(ScopesP callerScope){
	
    TypesP checkType;
    int ctr;
    std::stringstream labelst;
    string identifier;
    
	switch (currTok) {
			
		//Production 26 - ID<STCONT> 
		case ID:
			
			if(match(ID) == false){
				cerr << "identifier missing.\n";
				return false;
			}
                        
                        if(!(ExtendedSymbolTable::getInstance()->exists(ExtendedSymbolTable::getInstance()->getLastId()))){
                                Writer::getInstance()->errorReport(UNDEFID,ExtendedSymbolTable::getInstance()->getLastId());
                                return false;
                        }
                        
                                              
                                               
                        //Type(<STCONT>) = SysTable.getTypeOf(ID)
                        checkType = ExtendedSymbolTable::getInstance()->getSymbolTableAttributes(ExtendedSymbolTable::getInstance()->getLastId()).getTypeP();
			
			if(stcontP(callerScope,checkType,ExtendedSymbolTable::getInstance()->getLastId()) == false){
				return false;
			}
			
			break;
		
		//Production 27 - <BLOCK>
		case BLK_INIT:
			
			if(blockP(callerScope) == false){
				return false;
			}
			
			break;
		
		//Production 28 - if <EXPRESSION> then <STATEMENT> else <STATEMENT>
		case IF:
			
			Writer::getInstance()->setIfCtr(Writer::getInstance()->getIfCtr()+1);
			
			if(match(IF) == false){
				cerr << "if keyword missing.\n";
				return false;
			}
			
                        ctr = Writer::getInstance()->getIfCtr();
			
			if(expressionP(callerScope,checkType) == false){
				return false;
			}
                        
                        if(checkType != BOOLT){
                            Writer::getInstance()->errorReport(IFMIS,"");
                            return false;
                        }
                        
                        labelst << "else_" << ctr;
                                                
			Writer::getInstance()->condFalseJumpTo(labelst.str());
			
                        labelst.str(string());
                        
			if(match(THEN) == false){
				cerr << "then keyword missing.\n";
				return false;
			}
			
			if(statementP(callerScope) == false){
				return false;
			}
                        
                        labelst << "afterelse_" << ctr;
			
			Writer::getInstance()->uncondJumpTo(labelst.str());
			
                        labelst.str(string());
                        
                        labelst << "else_" << ctr;
                        
                        Writer::getInstance()->defLabel(labelst.str());
			
                        labelst.str(string());
                        
			if(match(ELSE) == false){
				cerr << "else keyword missing.\n";
				return false;
			}
			
			if(statementP(callerScope) == false){
				return false;
			}
			
                        labelst << "afterelse_" << ctr;
                        
			Writer::getInstance()->defLabel(labelst.str());
			
                        labelst.str(string());
                        
			break;
		
		//Production 29 - while <EXPRESSION> do <STATEMENT> 
		case WHILE:
			
			Writer::getInstance()->setLoopCtr(Writer::getInstance()->getLoopCtr()+1);
			
			if(match(WHILE) == false){
				cerr << "while keyword missing.\n";
				return false;
			}
			
                        ctr = Writer::getInstance()->getLoopCtr();
                        
                        labelst << "loop_" << ctr;
                                                
			Writer::getInstance()->defLabel(labelst.str());
			
                        labelst.str(string());
                        
			if(expressionP(callerScope,checkType) == false){
				return false;
			}
                        
                        if(checkType != BOOLT){
                            Writer::getInstance()->errorReport(WHILEMIS,"");
                            return false;
                        }
			
                        labelst << "exit_" << ctr;
                        
			Writer::getInstance()->condFalseJumpTo(labelst.str());
                        
                        labelst.str(string());
			
			if(match(DO) == false){
				cerr << "do keyword missing.\n";
				return false;
			}
			
			if(statementP(callerScope) == false){
				return false;
			}
                        
			labelst << "loop_" << ctr;
                        
			Writer::getInstance()->uncondJumpTo(labelst.str());
                        
                        labelst.str(string());
			
                        labelst << "exit_" << ctr;
                        
                        Writer::getInstance()->defLabel(labelst.str());
                        
                        labelst.str(string());
			
			break;
		
		//Production 30 - read(ID) 
		case READ:
                        
                        int destAddr;
			
			if(match(READ) == false){
				cerr << "while keyword missing.\n";
				return false;
			}
			
			if(match(LST_INIT) == false){
				cerr << "( missing.\n";
				return false;
			}
			
			if(match(ID) == false){
				cerr << "identifier missing.\n";
				return false;
			}
			
                        identifier = ExtendedSymbolTable::getInstance()->getLastId();
                        
                        if(!(ExtendedSymbolTable::getInstance()->exists(ExtendedSymbolTable::getInstance()->getLastId()))){
                                Writer::getInstance()->errorReport(UNDEFID,ExtendedSymbolTable::getInstance()->getLastId());
                                return false;
                        }
                        
                        if(ExtendedSymbolTable::getInstance()->getSymbolTableAttributes(ExtendedSymbolTable::getInstance()->getLastId()).getTypeP() != INTT){
                                Writer::getInstance()->errorReport(READMIS,ExtendedSymbolTable::getInstance()->getLastId());
                                return false;
                        }
                        
                        if(!(ExtendedSymbolTable::getInstance()->checkScope(ExtendedSymbolTable::getInstance()->getLastId()))){
                                Writer::getInstance()->errorReport(SCOPEMIS,ExtendedSymbolTable::getInstance()->getLastId());
                                return false;
                        }
                        
                        
                        destAddr = (ExtendedSymbolTable::getInstance()->getSymbolTableAttributes(ExtendedSymbolTable::getInstance()->getLastId())).getAddress();
                        
			if(match(LST_END) == false){
				cerr << ") missing.\n";
				return false;
			}
			
                        
                        Writer::getInstance()->readToTop();
                       
                        if(callerScope == GLOBALS){
                                (ExtendedSymbolTable::getInstance()->getSymbolTableAttributes(ExtendedSymbolTable::getInstance()->getLastId())).getTypeP() == INTT ? Writer::getInstance()->storeIntInScope(destAddr) : Writer::getInstance()->storeBoolInScope(destAddr);                        
                            }
                            else{
                                if(ExtendedSymbolTable::getInstance()->getSymbolTableAttributes(identifier).getScopeP() == GLOBALS){
                                (ExtendedSymbolTable::getInstance()->getSymbolTableAttributes(ExtendedSymbolTable::getInstance()->getLastId())).getTypeP() ? Writer::getInstance()->storeIntOutScope(destAddr) : Writer::getInstance()->storeBoolOutScope(destAddr);
                                }
                                else{
                                (ExtendedSymbolTable::getInstance()->getSymbolTableAttributes(ExtendedSymbolTable::getInstance()->getLastId())).getTypeP() == INTT ? Writer::getInstance()->storeIntInScope(STACKOFFSET+destAddr) : Writer::getInstance()->storeBoolInScope(STACKOFFSET+destAddr);
                                }
                            }
                        
			break;
			
		//Production 31 - write ( <EXPRESSION> )
		case WRITE:
			
			if(match(WRITE) == false){
				cerr << "while keyword missing.\n";
				return false;
			}
			
			if(match(LST_INIT) == false){
				cerr << "( missing.\n";
				return false;
			}
			
			if(expressionP(callerScope,checkType) == false){
				return false;
			}
                        
                        if(checkType != INTT){
                            Writer::getInstance()->errorReport(WRITEMIS,"");
                            return false;
                        }
			
			if(match(LST_END) == false){
				cerr << ") missing.\n";
				return false;
			}
			
                        Writer::getInstance()->printTop();
                        
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}

bool Compiler::stcontP(ScopesP callerScope,TypesP type,string identifier){
	
    TypesP exprType;
    int destAddr;
    
	switch (currTok) {
			
		//Production 32 - :=<EXPRESSION>
		case ASSIGN:
                        if(!ExtendedSymbolTable::getInstance()->checkScope(identifier)){
                                Writer::getInstance()->errorReport(SCOPEMIS,identifier);
                                return false;
                        }
                    
                        if(ExtendedSymbolTable::getInstance()->getSymbolTableAttributes(identifier).getTypeP() == PROCT){
                                Writer::getInstance()->errorReport(PROCLEFT,identifier);
                                return false;
                        }
                        
                                            
			if(match(ASSIGN) == false){
				cerr << ":= missing.\n";
				return false;
			}
                        
                        			
			if(expressionP(callerScope,exprType) == false){
				return false;
			}
                        
                        if(type != exprType){
                                Writer::getInstance()->errorReport(ASSIGNMIS,"");
                                return false;
                        }
                        
                        destAddr = ExtendedSymbolTable::getInstance()->getSymbolTableAttributes(identifier).getAddress();
                        
                        if(callerScope == GLOBALS){
                                type == INTT ? Writer::getInstance()->storeIntInScope(destAddr) : Writer::getInstance()->storeBoolInScope(destAddr);                        
                            }
                            else{
                                if(ExtendedSymbolTable::getInstance()->getSymbolTableAttributes(identifier).getScopeP() == GLOBALS){
                                type == INTT ? Writer::getInstance()->storeIntOutScope(destAddr) : Writer::getInstance()->storeBoolOutScope(destAddr);
                                }
                                else{
                                type == INTT ? Writer::getInstance()->storeIntInScope(STACKOFFSET+destAddr) : Writer::getInstance()->storeBoolInScope(STACKOFFSET+destAddr);
                                }
                            }
                        
			
			break;
			
			
		//Production 33  - <CALLEXP>
		case LST_INIT:
			
			if(callexpP(callerScope,type,identifier) == false){
				return false;
			}
			
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}

bool Compiler::callexpP(ScopesP callerScope,TypesP type,string identifier){
    
    int parNum;
    int sourceAddr;
    
	switch (currTok) {
		//Production 34 - ( <EXPRESSIONLIST> )
		case LST_INIT:
			
			if(match(LST_INIT) == false){
				cerr << "( missing.\n";
				return false;
			}
                        
                        if(callerScope == GLOBALS){
                                Writer::getInstance()->allocSF(0);
                        }
                        else{
                                Writer::getInstance()->allocSF(1);
                        }
			
			if(expressionlistP(callerScope) == false){
				return false;
			}
                        
                        //Check of number and order of parameters
                        if(!(ExtendedSymbolTable::getInstance()->checkCallParameters(identifier))){
                            return false;
                        }
			
			if(match(LST_END) == false){
				cerr << ") missing.\n";
				return false;
			}
                        
                        parNum = (ExtendedSymbolTable::getInstance()->getFunctionParameters(identifier)).size();
                        
                        Writer::getInstance()->callFunc(parNum,identifier);
			
			break;
			
			
		//Production 35  - ε
                case AND:
                case MUL:
                case DIV:
                case PLUS:
		case MINUS:
		case OR:
		case GT:
		case LT:
		case GE:
		case LE:
		case EQ:
		case NE:
		case EXPR_SEP:
		case ISTR_SEP:
		case LST_END:
		case DO:
		case THEN:
                case ELSE:
		case BLK_END:
		                        
			if(!(ExtendedSymbolTable::getInstance()->getSymbolTableAttributes(identifier).getRoutineFlag())){
                            
                            if(!ExtendedSymbolTable::getInstance()->checkScope(identifier)){
                                Writer::getInstance()->errorReport(SCOPEMIS,ExtendedSymbolTable::getInstance()->getLastId());
                                return false;
                            }
                            
                            sourceAddr = ExtendedSymbolTable::getInstance()->getSymbolTableAttributes(identifier).getAddress();
                            if(callerScope == GLOBALS){
                                type == INTT ? Writer::getInstance()->movIntTopInScope(sourceAddr) : Writer::getInstance()->movBoolTopInScope(sourceAddr);                        
                            }
                            else{
                                if(ExtendedSymbolTable::getInstance()->getSymbolTableAttributes(identifier).getScopeP() == GLOBALS){
                                type == INTT ? Writer::getInstance()->movIntTopOutScope(sourceAddr) : Writer::getInstance()->movBoolTopOutScope(sourceAddr);
                                }
                                else{
                                type == INTT ? Writer::getInstance()->movIntTopInScope(STACKOFFSET+sourceAddr) : Writer::getInstance()->movBoolTopInScope(STACKOFFSET+sourceAddr);    
                                }
                            }
                        }
                        else{
                            
                            if(!(ExtendedSymbolTable::getInstance()->checkCallParameters(identifier))){
                                return false;
                            }
                                                        
                            if(callerScope == GLOBALS){
                                Writer::getInstance()->allocSF(0);
                            }
                            else{
                                Writer::getInstance()->allocSF(1);
                            }
                            
                            parNum = ExtendedSymbolTable::getInstance()->getFunctionParameters(identifier).size();
                            Writer::getInstance()->callFunc(parNum,identifier);
                           
                            
                        }
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}

bool Compiler::expressionlistP(ScopesP callerScope){

   TypesP collectType; 
    
	switch (currTok) {
		//Production 36 - <EXPRESSION><EXLIST1>
		case ID:
		case NUM:
		case TRUEB:
		case FALSEB:
		case BLK_INIT:
		case MINUS:
		case NOT:
			
			if(expressionP(callerScope,collectType) == false){
				return false;
			}
                        
                        ExtendedSymbolTable::getInstance()->pushType(collectType);
			
			if(exlist1P(callerScope) == false){
				return false;
			}
			
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}

bool Compiler::exlist1P(ScopesP callerScope){
    
	switch (currTok) {
			
		//Production 37 - , <EXPRESSIONLIST>
		case EXPR_SEP:
			
			if(match(EXPR_SEP) == false){
				cerr << ", missing.\n";
				return false;
			}
			
			if(expressionlistP(callerScope) == false){
				return false;
			}
			
			break;
			
			
		//Production 38  - ε
		case LST_END:
			//Code to execute
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}

bool Compiler::expressionP(ScopesP callerScope,TypesP& type){

    TypesP c1Type;
    
	switch (currTok) {
		//Production 39 - <C1><C2>
		case ID:
		case NUM:
		case TRUEB:
		case FALSEB:
		case LST_INIT:
		case MINUS:
		case NOT:
			
                        
                        
			if(c1P(callerScope,c1Type) == false){
				return false;
			}
                                         
			//TypeH(<C2>) = Type(<C1>) 
			if(c2P(callerScope,type,c1Type) == false){
				return false;
			}
			//Type(<EXPRESSION>) = TypeS(<C2>)
                        
                        
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}

bool Compiler::c1P(ScopesP callerScope,TypesP& type){
	
	switch (currTok) {
		//Production 40 - <T>
		case ID:
		case NUM:
		case TRUEB:
		case FALSEB:
		case LST_INIT:
		case MINUS:
		case NOT:
			
                        
			if(tP(callerScope,type) == false){
				return false;
			}
			//Type(<C1>) = Type(<T>)
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}

bool Compiler::c2P(ScopesP callerScope,TypesP& typeS,TypesP& typeH){
    
    TypesP tType;
    TypesP propBool=BOOLT;
    
	switch (currTok) {
		//Production 41 - ><T><C2>
		case GT:
			
			if(match(GT) == false){
				cerr << "> missing.\n";
				return false;
			}
			
			if(tP(callerScope,tType) == false){
				return false;
			}
                        
                        if(!(typeH == tType) || !(tType == INTT)){
                            Writer::getInstance()->errorReport(GRTMIS,"");
                            return false;
                        }
                        //if (TypeH(<C2>) == Type(<T>) && Type(<T>) == integer) 
                        //TypeH(<C21>) = boolean
                        //else error("Grt:Type Mismatch.")
			
			Writer::getInstance()->grtTop2();
			
			if(c2P(callerScope,typeS,propBool) == false){
				return false;
			}
			
			break;
		
		//Production 42 - <<T><C2>
		case LT:
			
			if(match(LT) == false){
				cerr << "< missing.\n";
				return false;
			}
			
			if(tP(callerScope,tType) == false){
				return false;
			}
                        
                        if(!(typeH == tType) || !(tType == INTT)){
                            Writer::getInstance()->errorReport(LESMIS,"");
                            return false;
                        }
			
			Writer::getInstance()->lesTop2();
			
			if(c2P(callerScope,typeS,propBool) == false){
				return false;
			}
			
			break;
		
		//Production 43 - >=<T><C2>
		case GE:
			
			if(match(GE) == false){
				cerr << ">= missing.\n";
				return false;
			}
			
			if(tP(callerScope,tType) == false){
				return false;
			}
                        
                        if(!(typeH == tType) || !(tType == INTT)){
                            Writer::getInstance()->errorReport(GEQMIS,"");
                            return false;
                        }
			
			Writer::getInstance()->geqTop2();
			
			if(c2P(callerScope,typeS,propBool) == false){
				return false;
			}
			
			break;
		
		//Production 44 - <=<T><C2>
		case LE:
			
			if(match(LE) == false){
				cerr << "<= missing.\n";
				return false;
			}
			
			if(tP(callerScope,tType) == false){
				return false;
			}
                        
                        if(!(typeH == tType) || !(tType == INTT)){
                            Writer::getInstance()->errorReport(LEQMIS,"");
                            return false;
                        }
			
			Writer::getInstance()->leqTop2();
			
			if(c2P(callerScope,typeS,propBool) == false){
				return false;
			}
			
			break;
		
		//Production 45 - <><T><C2>
		case NE:
			
			if(match(NE) == false){
				cerr << "<> missing.\n";
				return false;
			}
			
			if(tP(callerScope,tType) == false){
				return false;
			}
                        
                        if(!(typeH == tType) || !(tType == INTT)){
                            Writer::getInstance()->errorReport(NEQMIS,"");
                            return false;
                        }
                        
			
			Writer::getInstance()->neqTop2();
			
			if(c2P(callerScope,typeS,propBool) == false){
				return false;
			}
			
			break;
		
		//Production 46 - =<T><C2>
		case EQ:
			
			if(match(EQ) == false){
				cerr << "= missing.\n";
				return false;
			}
			
			if(tP(callerScope,tType) == false){
				return false;
			}
                        
                        if(!(typeH == tType) || !(tType == INTT)){
                            Writer::getInstance()->errorReport(EQUMIS,"");
                            return false;
                        }
                        			
			Writer::getInstance()->equTop2();
			
			if(c2P(callerScope,typeS,propBool) == false){
				return false;
			}
			
			break;
		
		//Production 47  - ε
		case EXPR_SEP:
		case ISTR_SEP:
		case LST_END:
		case DO:
		case THEN:
                case ELSE:    
		case BLK_END:
			typeS = typeH;
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	
	
	return true;
}


bool Compiler::tP(ScopesP callerScope,TypesP& type){
    
    TypesP c3Type;
    
	switch (currTok) {
		//Production 48 - <C3><C4>
		case ID:
		case NUM:
		case TRUEB:
		case FALSEB:
		case LST_INIT:
		case MINUS:
		case NOT:
			
			if(c3P(callerScope,c3Type) == false){
				return false;
			}
			
			if(c4P(callerScope,type,c3Type) == false){
				return false;
			}
			
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}

bool Compiler::c3P(ScopesP callerScope,TypesP& type){
	
	switch (currTok) {
		//Production 49 - <F>
		case ID:
		case NUM:
		case TRUEB:
		case FALSEB:
		case LST_INIT:
		case MINUS:
		case NOT:
			
			if(fP(callerScope,type) == false){
				return false;
			}
			
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}

bool Compiler::c4P(ScopesP callerScope,TypesP& typeS,TypesP& typeH){

    TypesP fType;
    TypesP propBool = BOOLT;
    TypesP propInt = INTT;
    
	switch (currTok) {
		//Production 50 - +<F><C4>
		case PLUS:
			
			if(match(PLUS) == false){
				cerr << "+ missing.\n";
				return false;
			}
			
			if(fP(callerScope,fType) == false){
				return false;
			}
                        
                        
                        if(!(typeH == fType) || !(fType == INTT)){
                            Writer::getInstance()->errorReport(ADDMIS,"");
                            return false;
                        }
                        
                        		
			Writer::getInstance()->addTop2();
			
			if(c4P(callerScope,typeS,propInt) == false){
				return false;
			}
			
			break;
			
		//Production 51 - or<F><C4>
		case OR:
			
			if(match(OR) == false){
				cerr << "or keyword missing.\n";
				return false;
			}
			
			if(fP(callerScope,fType) == false){
				return false;
			}
                        
                        if(!(typeH == fType) || !(fType == BOOLT)){
                            Writer::getInstance()->errorReport(ORMIS,"");
                            return false;
                        }
			
			Writer::getInstance()->orTop2();
			
			if(c4P(callerScope,typeS,propBool) == false){
				return false;
			}
			
			break;
		
		//Production 52 - -<F><C4>
		case MINUS:
			
			if(match(MINUS) == false){
				cerr << "- missing.\n";
				return false;
			}
			
			if(fP(callerScope,fType) == false){
				return false;
			}
                        
                        if(!(typeH == fType) || !(fType == INTT)){
                            Writer::getInstance()->errorReport(SUBMIS,"");
                            return false;
                        }
			
			Writer::getInstance()->subTop2();
			
			if(c4P(callerScope,typeS,propInt) == false){
				return false;
			}
			
			break;
			
		
			
		//Production 53  - ε
		case GT:
		case LT:
		case GE:
		case LE:
		case EQ:
		case NE:
		case EXPR_SEP:
		case ISTR_SEP:
		case LST_END:
		case DO:
		case THEN:
                case ELSE:
		case BLK_END:
			typeS = typeH;
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	
	
	return true;
}


bool Compiler::fP(ScopesP callerScope,TypesP& type){
        
    TypesP c5Type;
    
	switch (currTok) {
		//Production 54 - <C5><C6>
		case ID:
		case NUM:
		case TRUEB:
		case FALSEB:
		case LST_INIT:
		case MINUS:
		case NOT:
			
			if(c5P(callerScope,c5Type) == false){
				return false;
			}
			
			if(c6P(callerScope,type,c5Type) == false){
				return false;
			}
			
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}

bool Compiler::c5P(ScopesP callerScope,TypesP& type){
	
	switch (currTok) {
		//Production 55 - <G>
		case ID:
		case NUM:
		case TRUEB:
		case FALSEB:
		case LST_INIT:
		case MINUS:
		case NOT:
			
			if(gP(callerScope,type) == false){
				return false;
			}
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	return true;
}

bool Compiler::c6P(ScopesP callerScope,TypesP& typeS,TypesP& typeH){
	
    TypesP gType;
    TypesP propBool = BOOLT;
    TypesP propInt = INTT;
    
    
	switch (currTok) {
		//Production 56 - *<G><C6>
		case MUL:
			
			if(match(MUL) == false){
				cerr << "* missing.\n";
				return false;
			}
			
			if(gP(callerScope,gType) == false){
				return false;
			}
                        
                        if(!(typeH == gType) || !(gType == INTT)){
                            Writer::getInstance()->errorReport(MULMIS,"");
                            return false;
                        }
			
			Writer::getInstance()->mulTop2();
			
			if(c6P(callerScope,typeS,propInt) == false){
				return false;
			}
			
			break;
			
		//Production 57 - and<G><C6>
		case AND:
			
			if(match(AND) == false){
				cerr << "and keyword missing.\n";
				return false;
			}
			
			if(gP(callerScope,gType) == false){
				return false;
			}
                        
                        if(!(typeH == gType) || !(gType == BOOLT)){
                            Writer::getInstance()->errorReport(ANDMIS,"");
                            return false;
                        }
			
			Writer::getInstance()->andTop2();
			
			if(c6P(callerScope,typeS,propBool) == false){
				return false;
			}
			
			break;
			
		//Production 58 - /<G><C6>
		case DIV:
			
			if(match(DIV) == false){
				cerr << "/ missing.\n";
				return false;
			}
			
			if(gP(callerScope,gType) == false){
				return false;
			}
                        
                        if(!(typeH == gType) || !(gType == INTT)){
                            Writer::getInstance()->errorReport(DIVMIS,"");
                            return false;
                        }
			
			Writer::getInstance()->divTop2();
			
			if(c6P(callerScope,typeS,propInt) == false){
				return false;
			}
			
			break;			
			
			
		//Production 59  - ε
		case PLUS:
		case MINUS:
		case OR:
		case GT:
		case LT:
		case GE:
		case LE:
		case EQ:
		case NE:
		case EXPR_SEP:
		case ISTR_SEP:
		case LST_END:
		case DO:
		case THEN:
                case ELSE:
		case BLK_END:
			typeS = typeH;
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	
	
	return true;
}

bool Compiler::gP(ScopesP callerScope,TypesP& type){
    
    SymbolTableAttributes test1;
    string test;
    TypesP exprType;
    
	switch (currTok) {
		//Production 60 - -<G>
		case MINUS:
			
			if(match(MINUS) == false){
				cerr << "- missing.\n";
				return false;
			}
			
			if(gP(callerScope,type) == false){
				return false;
			}
                        
                        if(type != INTT){
                            Writer::getInstance()->errorReport(NEGMIS,"");
                            return false;
                        }
			
			//CHECK POSITION!!!!
			Writer::getInstance()->negTop();
			
			break;
			
		//Production 61 - not<G>
		case NOT:
			
			if(match(NOT) == false){
				cerr << "not keyword missing.\n";
				return false;
			}
			
			if(gP(callerScope,type) == false){
				return false;
			}
                        
                        if(type != BOOLT){
                            Writer::getInstance()->errorReport(NEGMIS,"");
                            return false;
                        }
			
			//CHECK POSITION!!!!
			Writer::getInstance()->notTop();
			
			
			break;
		
		//Production 62 - ID<CALLEXP>
		case ID:
			
			if(match(ID) == false){
				cerr << "identifier missing.\n";
				return false;
			}
                        
                                               
                        if(!(ExtendedSymbolTable::getInstance()->exists(ExtendedSymbolTable::getInstance()->getLastId()))){
                                Writer::getInstance()->errorReport(UNDEFID,ExtendedSymbolTable::getInstance()->getLastId());
                                return false;
                        }
                        
                                               
                        type = ExtendedSymbolTable::getInstance()->getSymbolTableAttributes(ExtendedSymbolTable::getInstance()->getLastId()).getTypeP();
                        
                        if(type == PROCT){
                                Writer::getInstance()->errorReport(PROCINEXP,ExtendedSymbolTable::getInstance()->getLastId());
                                return false;
                        }
                        
			if(callexpP(callerScope,type,ExtendedSymbolTable::getInstance()->getLastId()) == false){
				return false;
			}
			
			break;
		
		//Production 63 - NUM
		case NUM:
			
			if(match(NUM) == false){
				cerr << "numerical value missing.\n";
				return false;
			}
			
                        type = INTT;
                        //Code production for integer const - Check for scope propagation
                        Writer::getInstance()->putIntTop(ExtendedSymbolTable::getInstance()->getLastNum());                        
			break;
			
		//Production 64 - true
		case TRUEB:
			
			if(match(TRUEB) == false){
				cerr << "boolean value missing.\n";
				return false;
			}
			
                        type = BOOLT;
			Writer::getInstance()->putBoolTop(true);
			
			
			break;
		
		//Production 65 - false
		case FALSEB:
			
			if(match(FALSEB) == false){
				cerr << "boolean value missing.\n";
				return false;
			}
			
                        type = BOOLT;
			Writer::getInstance()->putBoolTop(false);
			
			break;
			
		//Production 66 - ( <EXPRESSION> )
		case LST_INIT:
			
			if(match(LST_INIT) == false){
				cerr << "( missing.\n";
				return false;
			}
                        
			if(expressionP(callerScope,exprType) == false){
				return false;
			}
                     
                        type = exprType;
			
			if(match(LST_END) == false){
				cerr << ") missing.\n";
				return false;
			}
			
			break;
			
		default:Writer::getInstance()->errorReport(MSG,"Syntax error.");
			return false;
	}
	
	
	
	return true;
}
